package movee.spring.app.template.service;


import lombok.extern.slf4j.Slf4j;
import movee.spring.app.template.api.utils.ApiAssert;
import movee.spring.app.template.domain.api.ApiStatusCode;
import movee.spring.app.template.domain.api.CountedResponseData;
import movee.spring.app.template.domain.dao.ItemDao;
import movee.spring.app.template.domain.dao.JoinedItemDao;
import movee.spring.app.template.domain.dao.JoinedOrderDao;
import movee.spring.app.template.domain.dao.OrderDao;
import movee.spring.app.template.domain.query.JoinedItemQuery;
import movee.spring.app.template.domain.query.JoinedOrderQuery;
import movee.spring.app.template.domain.query.OrderSearchQuery;
import movee.spring.app.template.domain.repository.JoinedOrderRepo;
import movee.spring.app.template.domain.repository.OrderRepo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Nonnull;
import javax.persistence.criteria.Predicate;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * 提供操作单管理服务
 *
 * @author movee
 */
@Service
@Slf4j
public class OrderService {

    private final OrderRepo opRepo;
    private final JoinedOrderRepo joinedRepo;
    private final BeanCopier orderCopier;
    private final BeanCopier itemCopier;

    @Autowired
    public OrderService(OrderRepo opRepo, JoinedOrderRepo joinedRepo) {
        this.opRepo = opRepo;
        this.joinedRepo = joinedRepo;
        this.orderCopier = BeanCopier.create(JoinedOrderQuery.class, JoinedOrderDao.class, false);
        this.itemCopier = BeanCopier.create(JoinedItemQuery.class, JoinedItemDao.class, false);

    }

    public CountedResponseData<List<OrderDao>> search(@Nonnull OrderSearchQuery s) {

        // 构建查询条件
        Specification<OrderDao> spec = (r, cq, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (s.getId() != null) {
                predicates.add(cb.equal(r.get("id"), s.getId()));
            }

            if (!StringUtils.isEmpty(s.getName())) {
                predicates.add(cb.equal(r.get("name"), s.getName()));
            }

            if (!StringUtils.isEmpty(s.getCreateTime())) {
                predicates.add(cb.greaterThanOrEqualTo(r.get("createTime"), s.getCreateTime()));
            }

            if (!StringUtils.isEmpty(s.getUpdateTime())) {
                predicates.add(cb.greaterThanOrEqualTo(r.get("updateTime"), s.getUpdateTime()));
            }

            return cb.and(predicates.toArray(new Predicate[0]));
        };

        // 分页和排序
        Integer page = s.getPage();
        Integer pageSize = s.getPageSize();
        List<String> sort = s.getSort();
        ApiAssert.isTrue(page != null && page > 0, ApiStatusCode.INVALID_QUERY_PARAM,
                "pageNo must be more than 0. pageNo: " + page);
        ApiAssert.isTrue(pageSize != null && pageSize > 0, ApiStatusCode.INVALID_QUERY_PARAM,
                "pageNo must not be greater than 0. pageSize: " + pageSize);

        page = page - 1;
        String sortField = sort.size() == 0 ? "id" : sort.get(0);
        String sortDir = sort.size() >= 2 ? sort.get(1) : "asc";
        Pageable pageable = PageRequest.of(page, pageSize, Sort.by(Sort.Direction.fromString(sortDir), sortField));

        // 查询
        Page<OrderDao> entityPage = opRepo.findAll(spec, pageable);
        return new CountedResponseData<>(entityPage.getTotalElements(), entityPage.getContent());
    }


    public JoinedOrderDao getOrderDetailById(Long id) {
        return joinedRepo.getOne(id);
    }

    @Transactional
    public Long updateOrderDetail(JoinedOrderQuery query) {

        JoinedOrderDao order = new JoinedOrderDao();
        orderCopier.copy(query, order, null);

        List<JoinedItemDao> items = buildItems(query.getItems(), order);
        order.setItems(items);

        order = joinedRepo.saveAndFlush(order);

        return order.getId();
    }

    private List<JoinedItemDao> buildItems(List<JoinedItemQuery> itemQueries, JoinedOrderDao order) {
        List<JoinedItemDao> itemDaos = new ArrayList<>();
        if (!CollectionUtils.isEmpty(itemQueries)) {
            for (JoinedItemQuery itemQuery : itemQueries) {
                JoinedItemDao itemDao = new JoinedItemDao();
                itemCopier.copy(itemQuery, itemDao, null);
                itemDao.setOrder(order);

                itemDaos.add(itemDao);
            }
        }

        return itemDaos;
    }

}
